package main

import (
	"fmt"
	"os"
	"strings"
	"sync"
	"time"
	"github.com/go-ping/ping"
)

// add a lock for proxies operation
var checkProxyLock sync.Mutex

func initProxies(currentProxies *[]*Proxy, proxiesObj *[]*Proxy, config *Config) {
	// return if check is not enabled
	if !config.CheckEnabled {
		*currentProxies = *proxiesObj
		return
	}
	fmt.Println("Start to init proxies with health...")
	healthCheck(currentProxies, proxiesObj, config)
}

func checkProxies(currentProxies *[]*Proxy, proxiesObj *[]*Proxy, config *Config) {
	for {
		// sleep for a certain duration in config
		d := time.Duration(config.CheckDuration)*time.Second
		time.Sleep(d)
		fmt.Printf("[Health] %s Start to check proxies health... \n", time.Now().Format(time.RFC3339))
		healthCheck(currentProxies, proxiesObj, config)
	}
}

func healthCheck(currentProxies *[]*Proxy, proxiesObj *[]*Proxy, config *Config) {
	var tmpProxies []*Proxy
	for _, proxy := range *proxiesObj {
		// get split host and port
		hostWithPort := strings.Split(proxy.addr, ":")
		host := hostWithPort[0]

		// using ping to check health
		pingPong, err := ping.NewPinger(host)
		if err != nil {
			fmt.Printf("[Health] Error on pingPong: %s, err: %s\n", proxy.addr, err.Error())
			continue
		}
		pingPong.Count = config.CheckPingCount
		pingPong.Timeout = time.Duration(config.CheckPingCount)*time.Second
		pingPong.Run()
		stats := pingPong.Statistics()
		fmt.Printf("[Health] Check %s Finished: PacketLoss: %0.1f Average RTT: %s \n",
			proxy.addr, stats.PacketLoss, stats.AvgRtt.String())

		// add to available if Packet Loss Percentage < config.CheckLossPercentage
		if stats.PacketLoss < config.CheckLossPercentage {
			tmpProxies = append(tmpProxies, proxy)
		}
	}
	// copy proxies to currentProxies if not empty
	if len(tmpProxies) != 0 {
		// reset all available proxies's weight to zero
		checkProxyLock.Lock()
		for _, p := range tmpProxies {
			p.currentWeight = 0
		}
		*currentProxies = tmpProxies
		checkProxyLock.Unlock()
		fmt.Printf("[Health] %s: Check over, %d proxies are available.\n", time.Now().Format(time.RFC3339), len(tmpProxies))
	} else {
		fmt.Println("[Health] Error on health check, no proxy is valid on certain condition.")
		os.Exit(0)
	}
}